package com.xuecheng.content.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.content.mapper.TeachplanMapper;
import com.xuecheng.content.mapper.TeachplanMediaMapper;
import com.xuecheng.content.model.dto.BindTeachplanMediaDto;
import com.xuecheng.content.model.dto.SaveTeachplanDto;
import com.xuecheng.content.model.dto.TeachplanDto;
import com.xuecheng.content.model.po.Teachplan;
import com.xuecheng.content.model.po.TeachplanMedia;
import com.xuecheng.content.service.TeachplanService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

@Service
public class TeachplanServiceImpl extends ServiceImpl<TeachplanMapper, Teachplan> implements TeachplanService {

    @Autowired
    private TeachplanMapper teachplanMapper;

    @Autowired
    private TeachplanMediaMapper teachplanMediaMapper;

    /**
     * 课程计划service接口实现类
     *
     * @param courseId 课程id
     * @return
     */
    @Override
    public List<TeachplanDto> findTeachplanTree(Long courseId) {
        return teachplanMapper.selectTreeNodes(courseId);
    }

    /**
     * 保存课程计划
     *
     * @param saveTeachplanDto 课程计划dto
     */
    @Override
    public void saveTeachplan(SaveTeachplanDto saveTeachplanDto) {
        // 获取课程计划id
        Long id = saveTeachplanDto.getId();
        // 判断是新增还是修改
        if (id != null) {
            // 修改
            // 根据id查询数据库中原有数据
            Teachplan teachplan = teachplanMapper.selectById(id);
            // 将修改的新数据覆盖进去
            BeanUtils.copyProperties(saveTeachplanDto, teachplan);
            // 操作数据库，更新数据
            int updated = teachplanMapper.updateById(teachplan);
            // 判断更新是否成功
            if (updated != 1) XueChengPlusException.cast("更新课程信息失败");
        } else {
            // 新增
            // 创建课程计划对象
            Teachplan teachplan = new Teachplan();
            // 对象拷贝
            BeanUtils.copyProperties(saveTeachplanDto, teachplan);

            // 设置排序值
            // 获取父级id
            Long parentId = saveTeachplanDto.getParentid();
            // 获取课程id
            Long courseId = saveTeachplanDto.getCourseId();
            // 条件构造器
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            // 构造条件
            queryWrapper.eq(Teachplan::getCourseId, courseId).eq(Teachplan::getParentid, parentId);
            // 查询同级的个数
            Integer count = teachplanMapper.selectCount(queryWrapper);
            // 设置排序值
            teachplan.setOrderby(count + 1);

            // 操作数据库，新增数据
            int inserted = teachplanMapper.insert(teachplan);
            // 判断新增是否成功
            if (inserted != 1) XueChengPlusException.cast("新增课程信息失败");
        }
    }

    /**
     * 删除课程计划
     *
     * @param teachplanId 课程计划id
     */
    @Transactional
    @Override
    public void removeTeachplan(Long teachplanId) {
        // 判断课程计划id是否为空
        if (teachplanId == null) XueChengPlusException.cast("课程计划id为空");
        // 根据课程计划id查询数据库
        Teachplan teachplan = teachplanMapper.selectById(teachplanId);
        // 获取grade等级
        Integer grade = teachplan.getGrade();
        // 根据grade等级，判断删除的是大章节还是小章节
        if (grade == 1) {
            // 大章节
            // 判断大章节下无小章节才允许删除（根据课程计划id，查询数据库中父类id为课程计划id的）
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, teachplanId);
            Integer count = teachplanMapper.selectCount(queryWrapper);
            if (count > 0) XueChengPlusException.cast("课程计划信息还有子级信息，无法操作");
            // 无小章节，进行删除
            int deleted = teachplanMapper.deleteById(teachplanId);
            // 判断是否删除成功
            if (deleted != 1) XueChengPlusException.cast(teachplan.getPname() + " 删除失败");
        } else {
            // 小章节（需要连同小章节关联的媒资信息一起删除）
            // 根据课程计划id删除课程计划媒体信息表中对应的媒资信息
            LambdaUpdateWrapper<TeachplanMedia> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(TeachplanMedia::getTeachplanId, teachplanId);
            // 操作数据库，删除对应的媒资信息
            teachplanMediaMapper.delete(updateWrapper);
            // 操作数据库，删除小章节
            teachplanMapper.deleteById(teachplanId);
        }

    }

    /**
     * 课程计划排序（上下移动）
     *
     * @param moveType    移动类型
     * @param teachplanId 课程计划id
     */
    @Override
    public void orderByTeachplan(String moveType, Long teachplanId) {
        // 根据课程计划id查询课程计划表
        Teachplan teachplan = teachplanMapper.selectById(teachplanId);

        // 判断移动的是大章节还是小章节
        Integer grade = teachplan.getGrade();
        if (grade == 1) {
            // 大章节
            bigExchange(moveType, teachplan);
        } else {
            // 小章节
            smExchange(moveType, teachplan);
        }

    }

    /**
     * 教学计划-媒资绑定提交数据
     *
     * @param bindTeachplanMediaDto 教学计划-媒资绑定提交数据
     */
    @Transactional
    @Override
    public void associationMedia(BindTeachplanMediaDto bindTeachplanMediaDto) {
        // 教学计划id
        Long teachplanId = bindTeachplanMediaDto.getTeachplanId();
        // 根据教学计划id查询教学计划
        Teachplan teachplan = teachplanMapper.selectById(teachplanId);
        // 判断教学计划是否为空
        if (teachplan == null) {
            XueChengPlusException.cast("教学计划不存在");
        }
        // 获取课程等级
        Integer grade = teachplan.getGrade();
        if (grade != 2) {
            XueChengPlusException.cast("只允许第二级教学计划绑定媒资文件");
        }
        // 获取课程id
        Long courseId = teachplan.getCourseId();

        // 先删除原来该教学计划绑定的媒资
        teachplanMediaMapper.delete(new LambdaQueryWrapper<TeachplanMedia>().eq(TeachplanMedia::getTeachplanId, teachplanId));

        // 再添加教学计划与媒资的绑定关系
        TeachplanMedia teachplanMedia = new TeachplanMedia();
        teachplanMedia.setCourseId(courseId);
        teachplanMedia.setTeachplanId(teachplanId);
        teachplanMedia.setMediaFilename(bindTeachplanMediaDto.getFileName());
        teachplanMedia.setMediaId(bindTeachplanMediaDto.getMediaId());
        int inserted = teachplanMediaMapper.insert(teachplanMedia);
        if (inserted != 1) XueChengPlusException.cast("媒资绑定失败");
    }

    /**
     * 大章节移动
     *
     * @param moveType  移动类型
     * @param teachplan 课程计划对象
     */
    private void bigExchange(String moveType, Teachplan teachplan) {
        // 获取排序字段
        Integer orderby = teachplan.getOrderby();
        // 获取等级
        Integer grade = teachplan.getGrade();
        // 获取课程id
        Long courseId = teachplan.getCourseId();
        // 条件构造器
        LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();

        // 判断是上移还是下移
        if ("moveup".equals(moveType)) {
            // 上移
            // 判断是否已经位于顶部
            if (orderby == 1) XueChengPlusException.cast("已经到顶啦~");

            // 构造条件
            queryWrapper
                    .eq(Teachplan::getCourseId, courseId)
                    .eq(Teachplan::getGrade, grade)
                    .lt(Teachplan::getOrderby, orderby)
                    .orderByDesc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            // 查询数据库
            Teachplan one = teachplanMapper.selectOne(queryWrapper);

            // 上移交换位置
            exchangeUpOrderBy(teachplan, one, orderby);
        } else {
            // 下移
            // 构造条件
            queryWrapper
                    .eq(Teachplan::getCourseId, courseId)
                    .eq(Teachplan::getGrade, grade)
                    .gt(Teachplan::getOrderby, orderby)
                    .orderByAsc(Teachplan::getOrderby)
                    .last("LIMIT 1");
            // 查询数据库
            Teachplan one = teachplanMapper.selectOne(queryWrapper);

            // 判断是否已经是最底部
            if (one == null) XueChengPlusException.cast("已经到底啦！");

            // 下移交换位置
            exchangeDownOrderBy(teachplan, one, orderby);
        }
    }

    /**
     * 小章节移动
     *
     * @param moveType  移动类型
     * @param teachplan 课程计划对象
     */
    private void smExchange(String moveType, Teachplan teachplan) {
        // 获取排序字段
        Integer orderby = teachplan.getOrderby();
        // 获取父类id
        Long parentid = teachplan.getParentid();

        // 判断是上移还是下移
        if ("moveup".equals(moveType)) {
            // 上移
            // 判断是否已经位于顶部
            if (orderby == 1) XueChengPlusException.cast("已经到顶啦~");

            // 根据排序字段减一的操作，先查出上一级
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, parentid).eq(Teachplan::getOrderby, orderby - 1);
            Teachplan one = teachplanMapper.selectOne(queryWrapper);

            // 上移交换位置
            exchangeUpOrderBy(teachplan, one, orderby);
        } else {
            // 下移
            // 判断是否已经位于底部
            LambdaQueryWrapper<Teachplan> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Teachplan::getParentid, parentid);
            Integer count = teachplanMapper.selectCount(queryWrapper);
            if (Objects.equals(orderby, count)) XueChengPlusException.cast("已经到底啦~");

            // 根据排序字段加一的操作，先查出下一级
            queryWrapper.eq(Teachplan::getParentid, parentid).eq(Teachplan::getOrderby, orderby + 1);
            Teachplan one = teachplanMapper.selectOne(queryWrapper);

            // 下移交换位置
            exchangeDownOrderBy(teachplan, one, orderby);
        }
    }

    // 上移交换位置
    private void exchangeUpOrderBy(Teachplan teachplan, Teachplan one, Integer orderby) {
        // 与其上一级交换位置
        one.setOrderby(orderby);
        // 更新数据
        int updated = teachplanMapper.updateById(one);
        // 判断更新是否成功
        if (updated != 1) XueChengPlusException.cast("上移失败");
        // 将需要上移的章节的排序字段减一，并更新数据库
        teachplan.setOrderby(orderby - 1);
        // 更新数据库
        int updated1 = teachplanMapper.updateById(teachplan);
        // 判断更新是否成功
        if (updated1 != 1) XueChengPlusException.cast("上移失败");
    }

    // 下移交换位置
    private void exchangeDownOrderBy(Teachplan teachplan, Teachplan one, Integer orderby) {
        // 与其下一级交换位置
        one.setOrderby(orderby);
        // 更新数据
        int updated = teachplanMapper.updateById(one);
        // 判断更新是否成功
        if (updated != 1) XueChengPlusException.cast("下移失败");
        // 将需要下移的章节的排序字段加一，并更新数据库
        teachplan.setOrderby(orderby + 1);
        // 更新数据库
        int updated1 = teachplanMapper.updateById(teachplan);
        // 判断更新是否成功
        if (updated1 != 1) XueChengPlusException.cast("下移失败");
    }
}
